/**
 * \file   ts.cpp
 * \author Fabian Jesus Machado
 * \date   Septiembre de 2011
 * 
 *  Este archivo es parte del proyecto NPASM, un ensamblador para
 * microcontroladores PIC con sintaxis Intel, desarrollado inicialmente
 * por Fabian Machado (fabianjsm@gmail.com, twitter@fabianjsm).
 *  El codigo fuente esta diponible en el repositorio SVN de Google:
 *      http://npasm.googlecode.com/svn/trunk.
 * 
 * 
 */
#include <algorithm>
#include "ts.h"
using namespace std;
using namespace sblspace;

/**
 *  Construye una tabla raiz (padre de si misma) con el nombre
 * especificado.
 */
ts::ts(string _nombre)
{
	nombre = _nombre;
	padre = this;
}

/**
 *  Cronstruye una tabla hija de la tabla _padre con el nombre
 * espcificado.
 */
ts::ts(string _nombre, ts *_padre)
{
	nombre = _nombre;
	padre = _padre;
}

/**
 * Propiedad que devuelve la cantidad de simbolos que posee la tabla.
 */
int ts::GetCount()
{
	return lista.size();
}

/**
 * Propiedad que devuelve el nombre de la tabla.
 */
string ts::GetNombre()
{
	return nombre;
}

/**
 * Propiedad que devuelve el puntero al padre de la tabla.
 */
ts *ts::GetPadre()
{
	return padre;
}

/**
 *  Busca un simbolo local con el nombre especificado, devuelve cero o
 * un puntero valido.
 */
simbolo *ts::BuscarLocal(string _nombre)
{
	if(lista.size()) {
		sbl_list_iterator_t pos, fin = lista.end();
		if((pos = find(lista.begin(), fin, _nombre)) != fin)
			return &(*pos);
	}
	return 0;
}

/**
 *  Busca un simbolo publico con el nombre especificado, devuelve cero o
 * un puntero valido.
 */
simbolo *ts::Buscar(string _nombre)
{
	simbolo *sbl = BuscarLocal(_nombre);
	return sbl? sbl: (padre==this? 0: padre->Buscar(_nombre));
}

/**
 * Crea un simbolo local con el nombre especificado.
 */
simbolo *ts::insertarLocal(string _nombre)
{
	lista.insert(lista.begin(), _nombre);
	lista.sort();
	return &(*find(lista.begin(), lista.end(), _nombre));
}

/**
 *  Crea un simbolo local con el nombre espcificado. Si ya existe un
 * simbolo local con el nombre, retorna cero, en otro caso retorna un
 * puntero valido al simbolo creado.
 */
simbolo *ts::Insertar(string _nombre)
{
	simbolo *s = BuscarLocal(_nombre);
	return s? s: &(*insertarLocal(_nombre));
}

/**
 * Elimina el simbolo local con el nombre especificado y retorna true.
 * Si no lo encuentra retorna false.
 */
bool ts::Eliminar(string _nombre)
{
	if(!lista.size())
		return false;
	sbl_list_iterator_t pos, fin = lista.end();
	pos = find(lista.begin(), fin, _nombre);
	if(pos == fin)
		return false;
	lista.erase(pos);
	return true;
}

/**
 *  Busca el simbolo con el nombre especificado, tanto en el ambito
 * publico como el local. Si no lo encuetra lo crea en el ambito local.
 * Retorna un puntero valido o cero si falla.
 */
simbolo *ts::Simbolo(string _nombre)
{
	simbolo *s = Buscar(_nombre);
	return s? s: Insertar(_nombre);
}

/**
 * Busca el simbolo con el nombre especificado en el ambito local.
 * Retorna un puntero valido o cero si no lo encuentra.
 */
simbolo *ts::SimboloLocal(string _nombre)
{
	simbolo *s = BuscarLocal(_nombre);
	return s? s: insertarLocal(_nombre);
}

/**
 * Iterador al inicio de la lista de simbolos.
 */
sbl_list_iterator_t ts::GetSblInicio_iterator()
{
	return lista.begin();
}

/**
 * Iterador al final de la lista de simbolos.
 */
sbl_list_iterator_t ts::GetSblFin_iterator()
{
	return lista.end();
}

/**
 * Iterador al inicio de la lista de tablas.
 */
ts_list_iterator_t ts::GetTsInicio_iterator()
{
	return hijo.begin();
}

/**
 * Iterador al final de la lista de tablas.
 */
ts_list_iterator_t ts::GetTsFin_iterator()
{
	return hijo.end();
}

/**
 *  Busca una tabla hija con el nombre especificado. Si la encuentra
 * retorna un puntero valido a ella, en otro caso retorna cero.
 */
ts *ts::BuscarTabla(string _nombre)
{
	if(!hijo.size())
		return 0;
	ts_list_iterator_t h, fin;
	fin = hijo.end();
	h = find(hijo.begin(), fin, _nombre);
	return (h != fin)? &(*h): 0;
}

/**
 * Crea una tabla con el nombre especificado y retorna un puntero valido
 * a ella. Retorna cero si falla.
 */
ts *ts::NuevaTabla(string _nombre)
{
	ts *t = BuscarTabla(_nombre);
	if(t)
		return t;
	hijo.insert(hijo.begin(), ts(_nombre, this));
	ts_list_iterator_t h = find(hijo.begin(), hijo.end(), _nombre);
	return (h != hijo.end())? &(*h): 0;

}

/**
 *  Busca localmente una tabla con el nombre especificado, si no la
 * encuentra la crea. Retorna un puntero valido a la tabla creada o
 * encontrada, o cero si falla.
 */
ts *ts::Tabla(string _nombre)
{
	ts *t = BuscarTabla(_nombre);
	return t? t: NuevaTabla(_nombre);
}

/**
 *  Operador empleado para comparar tablas. Se considera que dos tablas
 * son iguales cuando poseen igual nombre. Se necesita para buscar
 * tablas empleando el algoritmo 'find' de la STL.
 */
bool ts::operator==(string _nombre)
{
	return nombre == _nombre;
}
